package linestrategy

import (
	"codejy/analysis/lineanalysis"
	"codejy/globalfunc"
	"codejy/store"
	"codejy/structdef"
	"codejy/utils"
	"strconv"
	"strings"
)

func init() {
	globalfunc.RegisterFuncAll("SubFunctionCallNameAndParam", SubFunctionCallNameAndParam)
	globalfunc.RegisterFuncAll("FunctionCallExecute", FunctionCallExecute)
	globalfunc.RegisterFuncAll("ParamTransition", ParamTransition)
	globalfunc.RegisterFuncAll("DefaultParamTransition", DefaultParamTransition)
	globalfunc.RegisterFuncAll("FunLineExecute", FunLineExecute)
}

// 定义函数调用策略
type FunctionCallStrategy struct {
}

// 注册策略
func init() {
	RegisterStrategy(&FunctionCallStrategy{})
}

// 判断是否是函数调用
func (f *FunctionCallStrategy) getId() int {
	return lineanalysis.FunctionCall
}
func (f *FunctionCallStrategy) Execute(threadStore *structdef.ThreadStore) {
	content := threadStore.Code.LineContent
	funName, funParams := SubFunctionCallNameAndParam(content)
	FunctionCallExecute(threadStore, funName, funParams)

}

func FunctionCallExecute(threadStore *structdef.ThreadStore, funName string, funParams []string) {
	//判断是否是默认函数
	exist := globalfunc.ExecuteFunc("IsFunDefaultExist", funName).(bool)
	if exist {
		//将参数转换为实际值,替换参数
		funParams = DefaultParamTransition(threadStore, funParams)
		//执行默认函数
		utils.CodeExecutionTime("默认函数耗时执行情况", threadStore, func() {
			globalfunc.ExecuteFunc("ExecuteStrategy", threadStore, funName, funParams)
		})

	} else {
		//不是默认函数 ,判断是否是类函数
		currentInstanceAddress := threadStore.CurrentInstanceAddress
		if currentInstanceAddress != "" {
			//获取类型方法定义
			prop, _ := store.GetInstanceProp(threadStore, currentInstanceAddress)
			typeName, _ := prop["@TYPENAME@"]  //获取实例的类型名称
			scope, _ := prop["@TYPEFILEPATH@"] //获取实例的类型名称
			typeDefinition := store.GetTypeDefinition(scope.Value, typeName.Value)
			definition, p := typeDefinition.Methods[funName]
			if !p {
				panic(currentInstanceAddress + "实例的类型" + funName + "未定义")
			}
			globalfunc.ExecuteFunc("ExecuteTypeMethod", threadStore, funName, definition, funParams)
		} else { //不是类函数,那么就是全局文件函数
			utils.CodeExecutionTime("函数耗时执行情况", threadStore, func() {
				//执行自定义函数
				executeCustomFunction(threadStore, funName, funParams)
			})
		}

	}
}
func executeCustomFunction(threadStore *structdef.ThreadStore, funName string, funParams []string) {
	//获取函数定义,函数定义是在当前文件中定义的
	definition := store.GetCurrentFunDefinition(threadStore, funName)
	if definition == nil {
		variable, b3 := store.GetVariable(threadStore, funName) //匿名函数获取
		if b3 {
			if variable.VarType == globalfunc.ExecuteFunc("GetFUNCDEF").(int) {
				funName = variable.Value
				definition = store.GetCurrentFunDefinition(threadStore, funName)
				if definition == nil {
					panic("错误::::::匿名函数未定义:" + funName + "(" + strings.Join(funParams, ",") + ")")
				}
			}
		} else {
			panic("错误::::::函数未定义:" + funName + "(" + strings.Join(funParams, ",") + ")")
		}

	}
	store.FuncStatusRestore(threadStore, func(parentEnv string, parentCodes []structdef.LineCodeDefinition, parentCode structdef.LineCodeDefinition) {
		//设置当前作用域,为函数名称
		store.AddCurrentEnv(threadStore, funName)
		//设置当前作用域的父作用域
		store.AddParentEnv(threadStore, parentEnv)
		//拿到函数体
		body := definition.Body
		FunLineExecute(threadStore, body, parentEnv, funName, funParams)
		//清除当前作用函数域的所有变量
		currentenv := threadStore.CurrentEnv
		store.DeleteVariableScope(threadStore, currentenv)
	})
}

// 函数行代码调用策略
func FunLineExecute(threadStore *structdef.ThreadStore, body []structdef.LineCodeDefinition, parentEnv, funName string, funParams []string) {
	ParamTransition(threadStore, funParams) //解析函数参数

	var isDefer = false
	var deferCodes []structdef.LineCodeDefinition
	//执行defer
	defer func() {
		//执行defer进行函数收尾
		if isDefer {
			//执行defer的代码
			FunLineExecute(threadStore, deferCodes, parentEnv, funName, funParams)
			//如果有错误,则执打印错误日志,并恢复错误,继续执行
			if err := recover(); err != nil {
				store.PrintExecuteCodeRecordLog(threadStore, err)
			}
		}

	}()
	// 策略模式,处理各种代码
	bodyLen := len(body)
	for i := 0; i < bodyLen; i++ {
		//分析当前操作行代码
		handleFilePath := threadStore.HandleFilePath
		definition := structdef.AnalyseLineCodeDefinition(threadStore, body[i], handleFilePath)
		//修改body
		body[i] = definition
		//设置当前函数所有行代码
		threadStore.Codes = body
		//设置当前函数操作指针,指针指向当前操作行
		threadStore.CurrentPoint = i
		//设置当前操作行
		threadStore.Code = body[i]

		//判断是否是defer
		if body[i].LineCodeType == lineanalysis.Defer && !isDefer {
			deferCodes = GetDeferCodes(threadStore, body, &i)
			isDefer = true
			continue
		}
		store.AddErrorLog(threadStore, store.NewRecordLog(threadStore, body[i])) //添加错误日志
		utils.LimitSpeed(threadStore)
		LineStrategyMode(threadStore) //策略模式,处理各种行代码
		//判断是否是to xx  ,这一步就是函数了,我们需要跳出函数
		if threadStore.ReturnFlag {
			threadStore.ReturnFlag = false
			return
		}
		//判断是否是ThreadStopFlag,如果是,则停止当前线程
		if threadStore.ThreadStopFlag {
			return
		}

		//跳过已经处理的行,调整指针位置
		i = threadStore.CurrentPoint

	}

}

// 不将参数注入函数作用域
func DefaultParamTransition(threadStore *structdef.ThreadStore, params []string) []string {
	//将参数转换为实际值,替换参数
	for i, param := range params {
		var v string
		//去除参数两边的空格
		if globalfunc.ExecuteFunc("IsFuncNameParameter", param).(bool) {
			//获取第一个等号的位置
			index := strings.Index(param, "=")
			//获取等号左边的值
			name := param[:index]
			//获取等号右边的值
			param = param[index+1:]
			v = globalfunc.ExecuteFunc("AssignmentStrategyMode", threadStore, param).(string)
			//替换参数
			param = name + "=" + v
			params[i] = param
		} else {
			v = globalfunc.ExecuteFunc("AssignmentStrategyMode", threadStore, param).(string)
			params[i] = v
		}
	}
	if len(params) > 0 {
		var list = make([]string, 0)
		for i := 0; i < len(params); i++ {
			if globalfunc.ExecuteFunc("IsFuncNameParameter", params[i]).(bool) {
				//获取第一个等号的位置
				index := strings.Index(params[i], "=")
				//获取等号右边的值
				v := params[i][index+1:]
				list = append(list, v)
			} else {
				list = append(list, params[i])
			}
		}
	}
	return params
}

// 函数参数解析参数,并且将参数以变量的形式存储到目标作用域内
func ParamTransition(threadStore *structdef.ThreadStore, params []string) []string {
	//将参数转换为实际值,替换参数
	for i, param := range params {
		var v string
		//去除参数两边的空格
		if globalfunc.ExecuteFunc("IsFuncNameParameter", param).(bool) {
			//获取第一个等号的位置
			index := strings.Index(param, "=")
			//获取等号左边的值
			name := param[:index]
			//获取等号右边的值
			param = param[index+1:]
			v = globalfunc.ExecuteFunc("AssignmentStrategyMode", threadStore, param).(string)
			//替换参数
			param = name + "=" + v
			params[i] = param
			//将共享类型注册到全局变量作用域中
			//存储变量
			var variableType = globalfunc.ExecuteFunc("CodeAnalysis", threadStore, v).(int)
			store.CreateAndModifyVariableScope(threadStore, threadStore.CurrentEnv, structdef.NewVarDefinitionValue(name, v, variableType))
		} else {
			v = globalfunc.ExecuteFunc("AssignmentStrategyMode", threadStore, param).(string)
			params[i] = v
		}
		//存储变量
		var variableType = globalfunc.ExecuteFunc("CodeAnalysis", threadStore, v).(int)
		store.CreateAndModifyVariableScope(threadStore, threadStore.CurrentEnv, structdef.NewVarDefinitionValue("$"+strconv.Itoa(i+1), v, variableType))
	}
	if len(params) > 0 {
		var list = make([]string, 0)
		var list1 = make([]string, 0) //不取消参数的命名
		for i := 0; i < len(params); i++ {
			list1 = append(list1, params[i])
			if globalfunc.ExecuteFunc("IsFuncNameParameter", params[i]).(bool) {
				//获取第一个等号的位置
				index := strings.Index(params[i], "=")
				//获取等号右边的值
				v := params[i][index+1:]
				list = append(list, v)
			} else {
				list = append(list, params[i])
			}
		}
		var addrList = globalfunc.ExecuteFunc("SliceToList", list, threadStore).(string)
		var variableType = globalfunc.ExecuteFunc("CodeAnalysis", threadStore, addrList).(int)
		store.CreateAndModifyVariableScope(threadStore, threadStore.CurrentEnv, structdef.NewVarDefinitionValue("$args", addrList, variableType))

		var addrList1 = globalfunc.ExecuteFunc("SliceToList", list1, threadStore).(string)
		var variableType1 = globalfunc.ExecuteFunc("CodeAnalysis", threadStore, addrList1).(int)
		store.CreateAndModifyVariableScope(threadStore, threadStore.CurrentEnv, structdef.NewVarDefinitionValue("$realArgs", addrList1, variableType1))

	}
	return params
}

// 函数调用表达式截取函数名称和参数
func SubFunctionCallNameAndParam(funCall string) (string, []string) {
	//获取第一个(的位置
	index := strings.Index(funCall, "(")
	//获取函数名
	funName := funCall[:index]
	//获取函数参数,去掉前后的()
	funParam := funCall[index+1 : len(funCall)-1]
	if funParam == "" {
		return funName, []string{}
	}
	//根据逗号分割参数
	funParams := utils.SplitFuncParams(funParam)
	return funName, funParams
}

// 获取Defer的代码
func GetDeferCodes(threadStore *structdef.ThreadStore, body []structdef.LineCodeDefinition, startIndex *int) []structdef.LineCodeDefinition {
	end := GetDeferCodeBlockEnd(threadStore, body, *startIndex+1) //获取Defer最后}的位置
	//获取Defer语句块的内容
	deferCodes := body[*startIndex+1 : end]
	//跳过Defer语句块
	*startIndex = end
	return deferCodes
}

// 获取Defer最后}的位置
func GetDeferCodeBlockEnd(threadStore *structdef.ThreadStore, codeBlocks []structdef.LineCodeDefinition, startIndex int) int {
	length := len(codeBlocks)
	var ifNum = 1
	var j int
	for j = startIndex; j < length; j++ {
		ifBlockCode := threadStore.Codes[j]
		lineContent := ifBlockCode.LineContent
		//截取Defer语句块的内容
		if strings.HasSuffix(lineContent, "{") {
			ifNum++
		}
		if strings.HasPrefix(lineContent, "}") {
			ifNum--
		}
		if ifNum == 0 {
			break
		}

	}
	return j
}
